namespace Game {
    using System.Collections;
    using System.IO;

    using UnityEngine;

    using XLua;

    using UA = UnityEngine.Application;

    public static class Lua {
        public static LuaEnv Env { get; private set; }

        public static IEnumerator OnInit() {
            Env = new LuaEnv();
            Env.AddLoader((ref string path) => {
#if UNITY_EDITOR
                return File.ReadAllBytes(Dir.LuaScriptsPath + path);
#else
                var asset = Assets.Load<TextAsset>(path);
                if (asset != null) return asset.bytes;
                return null;
#endif
            });

            Env.Global.Set("DEBUG", UA.isEditor);
            Env.Global.Set("CLIENT", true);

            Env.DoString("require 'Preload.lua'");

            yield return null;
        }

        public static T Get<T>(string name) {
            if (Env == null) {
                Logger.Error("Lua.Get<T> can NOT be called before Lua.OInit.");
                return default(T);
            }
            return Env.Global.Get<T>(name);
        }

        public static T GetInPath<T>(string path) {
            if (Env == null) {
                Logger.Error("Lua.GetInPath<T> can NOT be called before Lua.OInit.");
                return default(T);
            }
            return Env.Global.GetInPath<T>(path);
        }

        public static LuaTable NewTable() {
            if (Env == null) {
                Logger.Error("Lua.NewTable<T> can NOT be called before Lua.OInit.");
                return null;
            }
            return Env.NewTable();
        }

        public static void Call(string func, params object[] args) {
            if (Env == null) {
                Logger.Error("Lua.Call can NOT be called before Lua.OInit.");
                return;
            }

            LuaFunction f = Env.Global.GetInPath<LuaFunction>(func);
            if (f == null) {
                Logger.Error("Lua.Call(func, ...) failed. No such function named {0}.", func);
                return;
            }

            f.Invoke(args);
        }

        public static T Call<T>(string func, params object[] args) {
            if (Env == null) {
                Logger.Error("Lua.Call can NOT be called before Lua.OInit.");
                return default(T);
            }

            LuaFunction f = Env.Global.GetInPath<LuaFunction>(func);
            if (f == null) {
                Logger.Error("Lua.Call(func, ...) failed. No such function named {0}.", func);
                return default(T);
            }

            return f.Invoke<T>(args);
        }
    }
}
